import { ENUM_ERROR, RestDto } from "qqlx-core";
import { checkResponse, getDefaultResponse, parseErrorMessage } from "qqlx-cdk";

import { Logger } from "../lib/log";

/** 包装本地微服务的执行过程
 * @logger 是否需要打印执行耗时
 */
export function RpcResponse(path?: string, options?: { logger: boolean }) {
  // ⬇️⬇️仅仅会执行一次

  return function (target: object | Function, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>) {
    // 每次被修饰函数执行，⬇️⬇️都会执行
    const original = descriptor.value;

    descriptor.value = async function (...args: any[]) {
      const start = Date.now();
      const rest: RestDto = {
        traceInfo: {
          traceId: args[0]?.traceInfo?.traceId,
          traceIp: args[0]?.traceInfo?.traceIp,
          action: "🌸/✅ RPC-Local",
          path: path || "",
        },
        visitorId: args[0]?.visitorId,
        visitorType: args[0]?.visitorType,
      };

      const response = getDefaultResponse<null>();
      try {
        const data = await original.apply(this, args);
        response.code = ENUM_ERROR.SUCCESS;
        response.data = data;

        if (options?.logger) {
          const duration = Date.now() - start;
          Logger.info({ rest, log: `本地服务耗时=${duration}ms` });
          if (duration > 400) {
            const newTraceInfo: RestDto["traceInfo"] = { ...rest.traceInfo, action: "🌸/⚠️ RPC-Local" };
            Logger.warn({ rest: { ...rest, traceInfo: newTraceInfo }, log: "本次请求时间过长" });
          }
        }
      } catch (error) {
        const { code, message } = parseErrorMessage(error, { isQuick: true });
        response.code = code;
        response.message = message;

        const newTraceInfo: RestDto["traceInfo"] = { ...rest.traceInfo, action: "🌸/❌ RPC-Called" };
        Logger.error({ rest: { ...rest, traceInfo: newTraceInfo }, log: `本地服务错误（From ${(error as Error)?.stack}）`, detail: error as any });
        Logger.error({ rest: { ...rest, traceInfo: newTraceInfo }, log: "请求体", detail: { body: args } });
      }

      return response;
    };

    return descriptor;
  };
}

/** 等待远程服务的执行返回 { code/data/message }
 * @logger 是否需要打印等待耗时
 */
export function RpcWaiting<T>(path: string, options: { logger: boolean } = { logger: true }) {
  // ⬇️⬇️仅仅会执行一次

  return function (target: object | Function, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>) {
    // 每次被修饰函数执行，⬇️⬇️都会执行
    const original = descriptor.value;
    descriptor.value = async function (...args: any[]) {
      const start = Date.now();
      const traceInfo: RestDto["traceInfo"] = {
        traceId: args[0]?.traceInfo?.traceId,
        traceIp: args[0]?.traceInfo?.traceIp,
        action: "Ⓜ️/✅ RPC-Remote",
        path,
      };
      const rest: RestDto = { traceInfo, visitorId: args[0]?.visitorId, visitorType: args[0]?.visitorType };

      try {
        const res = await original.apply(this, args);

        if (options?.logger) {
          const duration = Date.now() - start;
          Logger.info({ rest, log: `远程服务耗时=${duration}ms` });
        }

        return checkResponse<T>(res);
      } catch (error) {
        const newTraceInfo: RestDto["traceInfo"] = { ...rest.traceInfo, action: "Ⓜ️/❌ RPC-Remote" };
        Logger.error({ rest: { ...rest, traceInfo: newTraceInfo }, log: `远程服务错误（From ${(error as Error)?.stack}）`, detail: error as any });
        Logger.error({ rest: { ...rest, traceInfo: newTraceInfo }, log: "请求体", detail: { body: { args } } });

        throw error;
      }
    };

    return descriptor;
  };
}
